package apis

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"github.com/go-admin-team/go-admin-core/sdk/api"
	"gorm.io/gorm"
	"net/http"
	"strconv"
	"strings"
	"time"
	models2 "tuowei.com/app/admin/models"
	"tuowei.com/app/api/models"
	"tuowei.com/app/api/service"
	"tuowei.com/app/api/service/dto"
	"tuowei.com/common/actions"
	"tuowei.com/pkg/util"
	"tuowei.com/pkg/xlog"
)

type ApiTestExercises struct {
	api.Api
	Base
}

type AutoGenerated struct {
	Single      string `json:"single"`
	Multi       string `json:"multi"`
	Judge       string `json:"judge"`
	Application string `json:"application"`
}

type questionType struct {
	SubjectType      string `json:"subject_type"`
	SubjectTypeLabel string `json:"subject_type_label"`
	//CompletedCount   int    `json:"completed_count"`
	//Count            int    `json:"count"`
}

func (e *ApiTestExercises) StartAnswer(c *gin.Context) {
	var err error
	req := dto.SubmitReq{}
	s := service.ApiTestExercises{}
	err = e.MakeContext(c).
		MakeOrm().
		Bind(&req, binding.JSON).
		MakeService(&s.Service).
		Errors
	if err != nil {
		xlog.Error(err)
		e.Error(500, err, err.Error())
		return
	}
	err, studentID := e.GetUser(&e.Api)
	if err != nil {
		xlog.Error(err)
		e.Error(401, err, err.Error())
		return
	}
	status, err := s.StartAnswer(&req, studentID)
	if status == 1 {
		xlog.Error(err)
		e.Error(500, err, err.Error())
		return
	} else if status == 2 {
		xlog.Error(err)
		e.Error(501, err, err.Error())
		return
	} else if status == 3 {
		e.Error(502, err, err.Error())
		return
	}

	e.OK(status, "成功")
	return
}

func (e ApiTestExercises) GetQuestionBankList(c *gin.Context) {
	req := dto.ApiExercisesGetPageReq{}
	s := service.ApiTestExercises{}
	s1 := service.ApiLearningList{}
	s2 := service.ApiCourseGift{}
	orderService := service.OrderService{}
	err := e.MakeContext(c).
		MakeOrm().
		Bind(&req, binding.Default(c.Request.Method, c.ContentType())).
		MakeService(&s.Service).
		MakeService(&s1.Service).
		MakeService(&s2.Service).
		MakeService(&orderService.Service).
		Errors
	if err != nil {
		e.Logger.Error(err)
		e.Error(500, err, err.Error())
		return
	}
	//数据权限检查
	p := actions.GetPermissionFromContext(c)
	list := make([]models.SysExercises, 0)
	var count int64

	err = s.GetPageQuestionBank(&req, p, &list, &count)
	if err != nil {
		e.Error(500, err, "查询失败")
		return
	}
	listReturn := make([]*models.SysQuestionBankReturn, 0)
	//获取每个练习题（章），对应整套题目（节）
	err, studentID := e.GetUser(&e.Api)
	if err != nil {
		e.Error(401, err, err.Error())
		return
	}
	arr, err := e.getCorrectRate(studentID)
	if err != nil {
		e.Error(500, err, "查询失败")
		return
	}
	objArr := orderService.GetAllCourseIds(studentID, "question_bank")
	if err != nil {
		e.PageOK(listReturn, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
		return
	}

	exercisesArr := make([]int, 0)
	for _, v := range list {
		exercisesArr = append(exercisesArr, v.Id)
	}
	var lists []*models.SysQuestionBankLink
	err = e.Orm.Where("link_type = ?", 2).Where("link_id in (?)", exercisesArr).Find(&lists).Error
	if err != nil {
		if !strings.EqualFold(err.Error(), gorm.ErrRecordNotFound.Error()) {
			e.Error(500, err, "查询失败")
			return
		}
	}
	maps := make(map[int][]string)
	countMap := make(map[int]int)
	for _, vs := range lists {
		tempArr := strings.Split(vs.QuestionBankStr, ",")
		if _, ok := maps[vs.LinkId]; ok {
			maps[vs.LinkId] = append(maps[vs.LinkId], tempArr...)
			countMap[vs.LinkId] = len(maps[vs.LinkId])
		} else {
			maps[vs.LinkId] = tempArr
			countMap[vs.LinkId] = len(tempArr)
		}

	}
	stuObj, err := e.GetUserObject(&e.Api)
	var serialNum string
	if err == nil && stuObj != nil {
		serialNum = stuObj.SerialNum
	}
	for _, l := range list {
		qbr := &models.SysQuestionBankReturn{}
		qbr.Id = l.Id
		qbr.Name = l.Name
		qbr.PublicRange = l.PublicRange
		qbr.Cover = l.Cover
		qbr.PublishRange = l.PublishRange
		qbr.Count = countMap[l.Id]
		qbr.Subject = l.Subject
		//qbr.Type = l.Type
		if studentID == 0 {
			qbr.CorrectRate = "0"
			qbr.Remark = "开始答题"
		} else {
			if arr[l.Id] == nil {
				qbr.CorrectRate = "0"
				qbr.Remark = "开始答题"
				qbr.RemarkLabel = "start"
			} else {
				qbr.CompleteCount = arr[l.Id].CompletedCount
				qbr.CorrectRate = strconv.Itoa(arr[l.Id].CorrectRate)
				qbr.Remark = arr[l.Id].Remark
			}
		}
		//00002 00003 是导入的学生，都特么是vip
		if !util.IsInArray(strconv.Itoa(l.Id), objArr) && !util.IsInArray(serialNum, []string{"00002", "00003"}) {

			qbr.Remark = "暂无权限"
			qbr.RemarkLabel = "no_auth"
		}

		listReturn = append(listReturn, qbr)
	}
	e.PageOK(listReturn, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
}

func (e ApiTestExercises) getCorrectRate(studentID int) (map[int]*models.CorrectRate, error) {
	var list []models.CorrectRate
	arr := make(map[int]*models.CorrectRate)
	err := e.Orm.Where("student_id = ?", studentID).Find(&list).Error
	if err != nil {
		xlog.Error(err)
		return nil, err
	}
	remark := ""
	remarkLabel := ""
	for _, v := range list {
		if v.Status == 1 {
			remark = "完成测试"
			remarkLabel = "completed"
		} else if v.Status == -1 {
			remark = "继续答题"
			remarkLabel = "continue"
		} else {
			remark = "开始答题"
			remarkLabel = "start"
		}
		arr[v.QuestionBankId] = &models.CorrectRate{
			QuestionBankId: v.QuestionBankId,
			CorrectRate:    v.CorrectRate,
			Remark:         remark,
			RemarkLabel:    remarkLabel,
			CompletedCount: v.CompletedMultipleCount + v.CompletedSingleCount + v.CompletedJudgmentCount + v.CompletedApplicationCount,
		}
	}
	return arr, nil
}

func (e ApiTestExercises) Detail(c *gin.Context) {
	req := dto.GetTestQuestionBankDetailById{}
	s := service.ApiTestExercises{}
	err := e.MakeContext(c).MakeOrm().Bind(&req, nil).MakeService(&s.Service).Errors
	if err != nil {
		xlog.Error(err)
		e.Error(500, err, err.Error())
		return
	}
	////检测用户是否购买过课程
	//err, studentID := e.GetUser(&e.Api)
	//if err != nil {
	//	xlog.Error(err)
	//	e.Error(401, err, err.Error())
	//	return
	//}
	//var student models.SysStudent
	//err = e.Orm.Model(student).First(&student, studentID).Error
	//if err != nil {
	//	xlog.Error(err)
	//	e.Error(500, err, err.Error())
	//	return
	//}
	//if student.OrderCount == 0 {
	//	text := "您尚未购买任何课程，暂时无法使用该题库进行练习"
	//	e.Error(500, errors.New(text), text)
	//	return
	//}
	err, studentID := e.GetUser(&e.Api)
	if err != nil {
		e.Error(http.StatusInternalServerError, err, err.Error())
		return
	}
	var list []models.QuestionBankWareTree
	list, err = s.QuestionBankWareTreeCall(req.GetId())
	chapterIds := make([]int, 0)
	for _, v := range list {
		if len(v.Children) > 0 {
			for _, vv := range v.Children {
				chapterIds = append(chapterIds, vv.Id)
			}
		}
	}
	// 获取所有子章节的练习记录
	if len(chapterIds) > 0 {
		chapterId2has := new(models2.PractiseChapterRecord).GetRecordsByChapterIds(e.Orm, studentID, chapterIds)
		for k, _ := range list {
			if len(list[k].Children) > 0 {
				for kk, _ := range list[k].Children {
					list[k].Children[kk].Learned = chapterId2has[list[k].Children[kk].Id]
				}
			}
		}
	}
	if err != nil {
		xlog.Error(err)
		e.Error(500, err, err.Error())
		return
	}

	e.OK(&list, "成功")
	return
}

func (e ApiTestExercises) GetQuestionTypeList(c *gin.Context) {
	//req := dto.GetQuestionTypeReq{}
	s := service.ApiTestExercises{}
	err := e.MakeContext(c).MakeOrm().
		//Bind(&req, binding.Form).
		MakeService(&s.Service).Errors
	if err != nil {
		xlog.Error(err)
		e.Error(500, err, err.Error())
		return
	}

	var data models.SysConfig
	var resp dto.GetSysConfigByKEYForServiceResp
	err = e.Orm.Table(data.TableName()).Where("config_key = ?", "question_bank_type").First(&resp).Error

	if err != nil {
		xlog.Error(err)
		e.Error(500, err, err.Error())
		return
	}

	temp := make(map[string]string)
	err = json.Unmarshal([]byte(resp.ConfigValue), &temp)

	if err != nil {
		xlog.Error(err)
		e.Error(500, err, err.Error())
		return
	}

	tmp := make([]*questionType, 0)
	for k, v := range temp {

		if k == "single" {
			tmp1 := &questionType{}
			tmp1.SubjectType = v
			tmp1.SubjectTypeLabel = k
			//tmp1.Count = questionBankWareModel.SingleChoiceCount
			tmp = append(tmp, tmp1)
		} else if k == "mutil" {
			tmp2 := &questionType{}
			tmp2.SubjectType = v
			tmp2.SubjectTypeLabel = k
			//tmp2.Count = questionBankWareModel.MultipleChoiceCount
			tmp = append(tmp, tmp2)
		} else if k == "judge" {
			tmp3 := &questionType{}
			tmp3.SubjectType = v
			tmp3.SubjectTypeLabel = k
			//tmp3.Count = questionBankWareModel.JudgmentQuestionCount
			tmp = append(tmp, tmp3)
		} else if k == "application" {
			tmp4 := &questionType{}
			tmp4.SubjectTypeLabel = k
			tmp4.SubjectType = v
			//tmp4.Count = questionBankWareModel.ApplicationQuestionsCount
			tmp = append(tmp, tmp4)
		}

	}

	e.OK(tmp, "成功")
	return

}

func (e ApiTestExercises) GetPracticeList(c *gin.Context) {
	req := dto.GetPracticeListByChapterIdReq{}
	s := service.ApiTestExercises{}
	err := e.MakeContext(c).
		MakeOrm().
		Bind(&req, binding.Default(c.Request.Method, c.ContentType())).
		MakeService(&s.Service).Errors
	if err != nil {
		xlog.Error(err)
		e.Error(500, err, err.Error())
		return
	}
	_, studentId := e.GetUser(&e.Api)
	list, err := s.GetPracticeList(&req, studentId)
	if err != nil {
		if strings.EqualFold(err.Error(), gorm.ErrRecordNotFound.Error()) {
			e.OK([]models.QuestionBankList{}, "无数据")
			return
		}
		e.Error(500, err, err.Error())
		return
	}
	var model models.SysExerciseRecord
	var lst []models.SysExerciseRecord
	//检测用户是否购买过课程
	err, studentID := e.GetUser(&e.Api)
	if err != nil {
		xlog.Error(err)
		e.Error(401, err, err.Error())
		return
	}
	db := e.Orm.Model(model).Where("student_id = ?", studentID)
	if req.ChapterId != 0 {
		db = db.Where("chapter_id = ?", req.ChapterId)
	}
	if req.SubjectType != "" {
		db = db.Where("subject_type = ?", req.SubjectType)
	}

	err = db.Where("ex_type = ?", req.ExerciseType).Find(&lst).Error
	var tmp = make(map[int]int)
	for _, vs := range lst {
		tmp[vs.ExId] = vs.Status
	}
	if err != nil {
		xlog.Error(err)
		e.Error(500, err, err.Error())
		return
	}
	for k, v := range list {
		list[k].Status = tmp[v.Id]
	}
	e.OK(list, "查询成功")
	return
}

func (e ApiTestExercises) GetAchievementReport(c *gin.Context) {
	req := dto.GetAchievementReportReq{}
	s := service.ApiTestExercises{}
	err := e.MakeContext(c).MakeOrm().Bind(&req, binding.Default(c.Request.Method, c.ContentType())).MakeService(&s.Service).Errors
	if err != nil {
		xlog.Error(err)
		e.Error(500, err, err.Error())
		return
	}
	var data models.SysPracticeRecord
	err, studentID := e.GetUser(&e.Api)
	if err != nil {
		xlog.Error(err)
		e.Error(401, err, err.Error())
		return
	}
	req.StudentId = studentID
	err = s.GetAchievementReport(&req, &data)
	if err != nil {
		xlog.Error(err)
		e.Error(500, err, err.Error())
		return
	}

	h, m, second := resolveTime(int(data.EndAnswerTime - data.StartAnswerTime))
	data.DurationStr = strconv.Itoa(h) + "时" + strconv.Itoa(m) + "分" + strconv.Itoa(second) + "秒"
	var counts int64
	db := e.Orm.Model(data).
		Where("student_id = ?", req.StudentId).
		Where("obj_id = ?", req.ObjId).
		Where("ex_type = ?", req.ExerciseType)

	if req.ChapterId != 0 {
		db = db.Where("chapter_id = ?", req.ChapterId)
	}
	err = db.Count(&counts).Error
	name := ""
	if req.ExerciseType == 1 {
		var object models.SysCourse
		e.Orm.Where("course_id = ?", req.ObjId).First(&object)
		name = object.Name
	} else if req.ExerciseType == 2 {
		var object models.SysExercises
		e.Orm.Where("id = ?", req.ObjId).First(&object)
		name = object.Name
	} else if req.ExerciseType == 3 {
		var object models.SysExamination
		e.Orm.Where("id = ?", req.ObjId).First(&object)
		name = object.Name
	}
	data.Name = name

	if err != nil {
		xlog.Error(err)
		e.Error(500, err, err.Error())
		return
	}
	data.NumberOfExercises = counts
	//获取答题卡记录
	var answerSheet []*models.ExerciseRecordList
	//var model models.SysExerciseRecord
	sql := ""
	switch req.ExerciseType {
	case 1:
		sql = "select * from (select er.*,l.name from (select * from `sys_exercise_record` where `ex_type` = ? and `link_id` = ? and `student_id` = ? and `practice_id` = ?) as er left join sys_course as  l on er.link_id = l.course_id) as s left join sys_question_bank as sb on s.ex_id = sb.id"
	case 2:
		sql = "select * from (select er.*, l.name from (select * from `sys_exercise_record` where `ex_type` = ? and `link_id` = ? and `student_id` = ? and `practice_id` = ?) as er left join sys_exercises as l on er.link_id = l.id) as s left join sys_question_bank as sb on s.ex_id = sb.id"
	case 3:
		sql = "select * from (select er.*, l.name from (select * from `sys_exercise_record` where `ex_type` = ? and `link_id` = ? and `student_id` = ? and `practice_id` = ?) as er left join sys_examination as l on er.link_id = l.id) as s left join sys_question_bank as sb on s.ex_id = sb.id"
	}
	sql += " order by s.id asc"
	err = e.Orm.Raw(sql, req.ExerciseType, req.ObjId, studentID, data.Id).Scan(&answerSheet).Error
	if err != nil {
		xlog.Error(err)
		e.Error(500, err, err.Error())
		return
	}

	var model models.SysQuestionBankLink
	db2 := e.Orm.Where("link_type = ?", req.ExerciseType).Where("link_id = ?", req.ObjId)

	if req.ChapterId != 0 {
		db2 = db2.Where("chapter_id = ?", req.ChapterId)
	}
	err = db2.First(&model).Error
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		xlog.Error(err)
		e.Error(500, err, err.Error())
		return
	}

	var questionBankData []*models.QuestionBankList
	err = e.Orm.Where("id in (?)", strings.Split(model.QuestionBankStr, ",")).Find(&questionBankData).Error
	if err != nil {
		xlog.Error(err)
		e.Error(500, err, err.Error())
		return
	}
	ints := make(map[int]bool, 0)
	for _, v := range answerSheet {
		ints[v.ExId] = true
	}

	for _, vs := range questionBankData {
		if !ints[vs.Id] {
			objects := &models.ExerciseRecordList{
				ExId:          vs.Id,
				SubjectType:   vs.SubjectType,
				Content:       vs.Content,
				CorrectAnswer: vs.CorrectAnswer,
				Analysis:      vs.Analysis,
				Status:        0,
				Answer:        vs.Answer,
			}
			answerSheet = append(answerSheet, objects)
		}
	}
	corretCount := int64(0)
	errorCount := int64(0)
	for _, v := range answerSheet {
		if v.Status == 1 {
			corretCount += 1
		} else {
			errorCount += 1
		}
	}

	count := len(answerSheet)
	if count == 0 {
		data.CorrectCount = 0
	} else {
		data.CorrectRate, _ = strconv.ParseFloat(fmt.Sprintf("%0.2f", float64(corretCount)/float64(count)*100), 64)
	}
	data.CorrectCount = corretCount
	data.ErrorCount = errorCount

	data.AnswerSheet = answerSheet
	e.OK(data, "查询成功")
	return
}

func (e ApiTestExercises) Submit(c *gin.Context) {
	req := dto.SubmitReq{}
	s := service.ApiTestExercises{}
	err := e.MakeContext(c).MakeOrm().Bind(&req, binding.JSON).MakeService(&s.Service).Errors
	if err != nil {
		xlog.Error(err)
		e.Error(500, err, err.Error())
		return
	}
	err, studentID := e.GetUser(&e.Api)
	if err != nil {
		xlog.Error(err)
		e.Error(401, err, err.Error())
		return
	}
	err = s.UpdatePracticeRecord(&req, studentID)
	if err != nil {
		xlog.Error(err)
		e.Error(500, err, err.Error())
		return
	}
	e.OK(nil, "成功")
	return
}

// 秒转换为日时分秒和补零操作
func resolveTime(seconds int) (hour, minute, second int) {
	var day = seconds / (24 * 3600)
	hour = (seconds - day*3600*24) / 3600
	minute = (seconds - day*24*3600 - hour*3600) / 60
	second = seconds - day*24*3600 - hour*3600 - minute*60
	return
}

func (e ApiTestExercises) AgainAnswerQuestion(c *gin.Context) {
	req := dto.AgainSubmitReq{}
	err := e.MakeContext(c).MakeOrm().Bind(&req, binding.JSON).Errors
	if err != nil {
		xlog.Error(err)
		e.Error(500, err, err.Error())
		return
	}
	var model models.SysPracticeRecord

	err, studentID := e.GetUser(&e.Api)
	if err != nil {
		xlog.Error(err)
		e.Error(401, err, err.Error())
		return
	}
	updates := map[string]interface{}{
		"start_answer_time": time.Now().Unix(),
		"end_answer_time":   0,
		"correct_count":     0,
		"error_count":       0,
	}
	err = e.Orm.Model(model).
		Where("obj_id = ?", req.ObjId).
		Where("student_id = ?", studentID).
		Where("ex_type = ?", req.ExerciseType).
		First(&model).Error
	if err != nil {
		xlog.Error(err)
		e.Error(500, err, err.Error())
		return
	}
	err = e.Orm.Model(model).
		Where("obj_id = ?", req.ObjId).
		Where("student_id = ?", studentID).
		Where("ex_type = ?", req.ExerciseType).
		Updates(&updates).Error
	if err != nil {
		xlog.Error(err)
		e.Error(500, err, err.Error())
		return
	}
	//异步删除已做练习题记录列表
	go func() {
		var obj models.SysExerciseRecord
		e.Orm.Model(obj).Where("student_id = ?", studentID).
			Where("link_id = ?", req.ObjId).
			Where("ex_type = ?", req.ExerciseType).Delete(&obj)
	}()
	e.OK(nil, "成功")
	return
}

func (e ApiTestExercises) NextQuestion(c *gin.Context) {
	req := dto.SysExerciseRecordInsertReq{}
	s := service.ApiExerciseRecord{}
	err := e.MakeContext(c).
		MakeOrm().
		Bind(&req, binding.JSON).
		MakeService(&s.Service).
		Errors
	if err != nil {
		xlog.Error(err)
		e.Error(500, err, err.Error())
		return
	}

	err, studentID := e.GetUser(&e.Api)
	if err != nil {
		xlog.Error(err)
		e.Error(401, err, err.Error())
		return
	}
	if req.ChapterId > 0 {
		e.Orm.Where("student_id = ?", studentID).Where("chapter_id = ?", req.ChapterId).FirstOrCreate(&models2.PractiseChapterRecord{
			StudentId: studentID,
			ChapterId: req.ChapterId,
		})
	}
	err = s.Insert(&req, studentID)
	if err != nil {
		xlog.Error(err)
		e.Error(500, err, err.Error())
		return
	}
	e.OK(nil, "成功")
	return
}

func (e ApiTestExercises) RecordPracticeLeave(c *gin.Context) {
	req := dto.RecordLeavePracticeReq{}
	s := service.ApiTestExercises{}
	err := e.MakeContext(c).
		MakeOrm().
		Bind(&req, binding.JSON).
		MakeService(&s.Service).
		Errors
	if err != nil {
		xlog.Error(err)
		e.Error(500, err, err.Error())
		return
	}
	err, studentID := e.GetUser(&e.Api)
	if err != nil {
		xlog.Error(err)
		e.Error(401, err, err.Error())
		return
	}
	err = s.RecordPracticeLeave(&req, studentID)
	if err != nil {
		xlog.Error(err)
		e.Error(500, err, err.Error())
		return
	}

	e.OK(nil, "Success")
	return
}
